#include "n32g031.h"
#include "DevicesDelay.h"
#include "DevicesSoftIIC.h"



SoftIICHandle g_SoftIIC6988Handle;



void vSoftIIC6998Init(void)
{
    GPIO_InitType GPIO_InitStructure = {0};


    /* GPIO Ports Clock Enable */
    RCC_EnableAPB2PeriphClk(RCC_APB2_PERIPH_GPIOB, ENABLE);


    g_SoftIIC6988Handle.SclGPIO = SOFT_IIC_6998_SCK_GPIO_Port;
    g_SoftIIC6988Handle.SclPin = SOFT_IIC_6998_SCK_Pin;

    g_SoftIIC6988Handle.SdaGPIO = SOFT_IIC_6998_SDA_GPIO_Port;
    g_SoftIIC6988Handle.SdaPin = SOFT_IIC_6998_SDA_Pin;

    g_SoftIIC6988Handle.GPIOSetMode = vSoftIICxSetSdaGPIOMode;
    g_SoftIIC6988Handle.GPIOSetHigh = GPIO_SetBits;
    g_SoftIIC6988Handle.GPIOSetLow = GPIO_ResetBits;
    g_SoftIIC6988Handle.GPIOReadBit = GPIO_ReadInputDataBit;

    g_SoftIIC6988Handle.delayTime = SOFT_IIC_6998_DELAY_BIT_TIME;


    /*Configure GPIO pin Output Level */
    GPIO_SetBits(g_SoftIIC6988Handle.SclGPIO, g_SoftIIC6988Handle.SclPin);
    GPIO_SetBits(g_SoftIIC6988Handle.SdaGPIO, g_SoftIIC6988Handle.SdaPin);

    /* -2- Configure GPIOx_PIN in output push-pull mode */
    GPIO_InitStruct(&GPIO_InitStructure);
    GPIO_InitStructure.Pin = g_SoftIIC6988Handle.SclPin;
    GPIO_InitStructure.GPIO_Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStructure.GPIO_Speed = GPIO_SPEED_HIGH;
    GPIO_InitStructure.GPIO_Pull = GPIO_PULL_UP;
    GPIO_InitPeripheral(g_SoftIIC6988Handle.SclGPIO, &GPIO_InitStructure);

    GPIO_InitStructure.Pin = g_SoftIIC6988Handle.SdaPin;
    GPIO_InitStructure.GPIO_Mode = GPIO_MODE_OUTPUT_OD;
    GPIO_InitPeripheral(g_SoftIIC6988Handle.SdaGPIO, &GPIO_InitStructure);
}




int8_t cSoftIICxBusReset(SoftIICHandle *pHandle, int32_t iTime)
{
    pHandle->GPIOSetLow(pHandle->SclGPIO, pHandle->SclPin);
    vDelayUs(iTime);
    pHandle->GPIOSetHigh(pHandle->SclGPIO, pHandle->SclPin);

    return 0;
}

void vSoftIICxSetSdaGPIOMode(struct SoftIICStruct *pHandle, uint32_t typeMode)
{
    GPIO_InitType GPIO_InitStructure = {0};

    GPIO_InitStruct(&GPIO_InitStructure);
    GPIO_InitStructure.Pin = pHandle->SdaPin;
    GPIO_InitStructure.GPIO_Mode = typeMode;
    GPIO_InitStructure.GPIO_Speed = GPIO_SPEED_HIGH;
    GPIO_InitStructure.GPIO_Pull = GPIO_PULL_UP;
    GPIO_InitPeripheral(pHandle->SdaGPIO, &GPIO_InitStructure);
}

void vSoftIICxStart(SoftIICHandle *pHandle)
{
    pHandle->GPIOSetHigh(pHandle->SdaGPIO, pHandle->SdaPin);
    vDelayUs(pHandle->delayTime);

    pHandle->GPIOSetHigh(pHandle->SclGPIO, pHandle->SclPin);
    vDelayUs(pHandle->delayTime);

    pHandle->GPIOSetLow(pHandle->SdaGPIO, pHandle->SdaPin);
    vDelayUs(pHandle->delayTime);

    pHandle->GPIOSetLow(pHandle->SclGPIO, pHandle->SclPin);
    vDelayUs(pHandle->delayTime);
}

void vSoftIICxStop(SoftIICHandle *pHandle)
{
    pHandle->GPIOSetLow(pHandle->SdaGPIO, pHandle->SdaPin);
    vDelayUs(pHandle->delayTime);

    pHandle->GPIOSetHigh(pHandle->SclGPIO, pHandle->SclPin);
    vDelayUs(pHandle->delayTime);

    pHandle->GPIOSetHigh(pHandle->SdaGPIO, pHandle->SdaPin);
    vDelayUs(pHandle->delayTime);
}

void vSoftIICxWriteACKState(SoftIICHandle *pHandle, uint8_t ucACKState)
{
    if(ucACKState == SORT_IIC_NACK)
        pHandle->GPIOSetHigh(pHandle->SdaGPIO, pHandle->SdaPin);
    else
        pHandle->GPIOSetLow(pHandle->SdaGPIO, pHandle->SdaPin);

    vDelayUs(pHandle->delayTime);

    pHandle->GPIOSetHigh(pHandle->SclGPIO, pHandle->SclPin);
    vDelayUs(pHandle->delayTime);

    pHandle->GPIOSetLow(pHandle->SclGPIO, pHandle->SclPin);
    vDelayUs(pHandle->delayTime);
}

uint8_t ucSoftIICxReadACKState(SoftIICHandle *pHandle)
{
    uint8_t ucACKState = SORT_IIC_NACK;

   pHandle->GPIOSetMode(pHandle, GPIO_MODE_INPUT);

    pHandle->GPIOSetHigh(pHandle->SdaGPIO, pHandle->SdaPin);
    vDelayUs(pHandle->delayTime);

    pHandle->GPIOSetHigh(pHandle->SclGPIO, pHandle->SclPin);
    vDelayUs(pHandle->delayTime);

    if(pHandle->GPIOReadBit(pHandle->SdaGPIO, pHandle->SdaPin) == 0)
        ucACKState = SORT_IIC_ACK;

    pHandle->GPIOSetLow(pHandle->SclGPIO, pHandle->SclPin);
    vDelayUs(pHandle->delayTime);

   pHandle->GPIOSetMode(pHandle, GPIO_MODE_OUTPUT_PP);

    return ucACKState;
}

void vSoftIICxWriteByte(SoftIICHandle *pHandle, uint8_t ucData)
{
    uint8_t ucMask = 0x80;

    for(ucMask = 0x80; ucMask; ucMask >>= 1)
    {
        if(ucData & ucMask)
            pHandle->GPIOSetHigh(pHandle->SdaGPIO, pHandle->SdaPin);
        else
            pHandle->GPIOSetLow(pHandle->SdaGPIO, pHandle->SdaPin);

        vDelayUs(pHandle->delayTime);

        pHandle->GPIOSetHigh(pHandle->SclGPIO, pHandle->SclPin);
        vDelayUs(pHandle->delayTime);

        pHandle->GPIOSetLow(pHandle->SclGPIO, pHandle->SclPin);
        vDelayUs(pHandle->delayTime);
    }
}

uint8_t ucSoftIICxReadByte(SoftIICHandle *pHandle)
{
    uint8_t ucMask = 0x80, ucData = 0x00;

   pHandle->GPIOSetMode(pHandle, GPIO_MODE_INPUT);
    pHandle->GPIOSetHigh(pHandle->SdaGPIO, pHandle->SdaPin);

    for(ucMask = 0x80; ucMask; ucMask >>= 1)
    {
        pHandle->GPIOSetHigh(pHandle->SclGPIO, pHandle->SclPin);
        vDelayUs(pHandle->delayTime);

        if(pHandle->GPIOReadBit(pHandle->SdaGPIO, pHandle->SdaPin) != 0)
            ucData |= ucMask;

        pHandle->GPIOSetLow(pHandle->SclGPIO, pHandle->SclPin);
        vDelayUs(pHandle->delayTime);
    }

   pHandle->GPIOSetMode(pHandle, GPIO_MODE_OUTPUT_PP);

    return ucData;
}

int8_t cSoftIICxWriteDatas(SoftIICHandle *pHandle, uint8_t ucAddr, uint8_t ucReg, uint8_t *pucDatas, uint32_t iLength)
{
    int32_t i = 0;
    int8_t cError = 0x01;

    for(i = 0; i < 32; ++i)
    {
        vSoftIICxStart(pHandle);

        vSoftIICxWriteByte(pHandle, ucAddr | SORT_IIC_WRITE_MODE);
        if(ucSoftIICxReadACKState(pHandle) == SORT_IIC_ACK)
        {
            cError = 0x00;
            break;
        }
        else
            vDelayUs(100);
    }

    vSoftIICxWriteByte(pHandle, ucReg);
    if(ucSoftIICxReadACKState(pHandle) != SORT_IIC_ACK)
        cError |= 0x02;

    for(i = 0; i < iLength; ++i)
    {
        vSoftIICxWriteByte(pHandle, *pucDatas++);
        if(ucSoftIICxReadACKState(pHandle) != SORT_IIC_ACK)
            cError |= 0x04;
    }

    vSoftIICxStop(pHandle);

    return cError;
}

int8_t cSoftIICxReadDatas(SoftIICHandle *pHandle, uint8_t ucAddr, uint8_t ucReg, uint8_t *pucDatas, int32_t iLength)
{
    int32_t i = 0;
    int8_t cError = 0x01;

    for(i = 0; i < 32; ++i)
    {
        vSoftIICxStart(pHandle);

        vSoftIICxWriteByte(pHandle, ucAddr | SORT_IIC_WRITE_MODE);
        if(ucSoftIICxReadACKState(pHandle) == SORT_IIC_ACK)
        {
            cError = 0x00;
            break;
        }
        else
            vDelayUs(100);
    }

    vSoftIICxWriteByte(pHandle, ucReg);
    if(ucSoftIICxReadACKState(pHandle) != SORT_IIC_ACK)
        cError |= 0x02;

    vSoftIICxStart(pHandle);

    vSoftIICxWriteByte(pHandle, ucAddr | SORT_IIC_READ_MODE);
    if(ucSoftIICxReadACKState(pHandle) != SORT_IIC_ACK)
        cError |= 0x04;

    iLength -= 1;
    for(i = 0; i < iLength; ++i)
    {
        *pucDatas++ = ucSoftIICxReadByte(pHandle);
        vSoftIICxWriteACKState(pHandle, SORT_IIC_ACK);
    }

    *pucDatas = ucSoftIICxReadByte(pHandle);
    vSoftIICxWriteACKState(pHandle, SORT_IIC_NACK);

    vSoftIICxStop(pHandle);

    return cError;
}
